#ifndef __M_CHANNEL_H__
#define __M_CHANNEL_H__

#pragma once

#include "log.hpp"
#include <iostream>
#include <functional>
#include <sys/epoll.h>

class Poller;
class EventLoop;

class Channel
{
public:
    using eventCallback = std::function<void()>;

private:
    /*
    channel模块要监听的事件以及事件就绪时的回调函数都由connection模块指定
    */
    int _fd;
    uint32_t _events;//要监听的事件
    uint32_t _revents;//就绪的事件
    EventLoop* _loop;
    eventCallback _readcb;//读事件就绪回调
    eventCallback _writecb;//写事件就绪回调
    eventCallback _errorcb;//错误事件就绪回调
    eventCallback _closecb;//连接关闭回调
    eventCallback _eventscb;//任意事件就绪回调

public:
    Channel(int fd, EventLoop* loop)
    : _fd(fd),
      _events(0),
      _revents(0),
      _loop(loop),
      _readcb(nullptr),
      _writecb(nullptr),
      _errorcb(nullptr),
      _closecb(nullptr),
      _eventscb(nullptr)
    {}

    bool isMonitorRead() { return _events & EPOLLIN; }//是否监控读事件

    bool isMonitorWrite() { return _events & EPOLLOUT; }//是否监控写事件

    void monitorRead() { _events |= EPOLLIN; updateEventMonitor(); }//设置读事件监控

    void monitorWrite() { _events |= EPOLLOUT; updateEventMonitor(); }//设置写事件监控

    void cancelMonitorRead() { _events &= ~EPOLLIN; updateEventMonitor(); }//取消读事件监控

    void cancelMonitorWrite() { _events &= ~EPOLLOUT; updateEventMonitor(); }//取消写事件监控

    void cancelMonitorAll() { _events = 0; updateEventMonitor(); }//取消监控所有事件

    void setRevents(uint32_t revents) { _revents = revents; }

    void setReadCallback(const eventCallback& readcb) { _readcb = readcb; }

    void setWriteCallback(const eventCallback& writecb) { _writecb = writecb; }

    void setErrorCallback(const eventCallback& errorcb) { _errorcb = errorcb; }

    void setCloseCallback(const eventCallback& closecb) { _closecb = closecb; }

    void setEventsCallback(const eventCallback& eventscb) { _eventscb = eventscb; }

    //由于在实现Channel类时还没有定义Poller类 所以不知道Poller类的成员 因此下面三个函数需要在Poller类定义完成后实现
    void updateEventMonitor();//将连接要监控的事件设置好之后 需要将连接对应的描述符添加到epoll模型中 若连接已经在epoll模型中 则optype为EPOLL_CTL_MOD
    void removeEventMonitor();

    uint32_t getEvent() { return _events; }

    int getFd() { return _fd; }

    void handleEvent()//事件处理函数
    {
        if (_revents & EPOLLIN || _revents & EPOLLRDHUP || _revents & EPOLLPRI)
        {
            if (_readcb != nullptr)
                _readcb();
        }
        else if (_revents & EPOLLOUT)
        {
            if (_writecb != nullptr)
                _writecb();
        }
        else if (_revents & EPOLLERR)
        {
            if (_errorcb != nullptr)
                _errorcb();
        }
        else if (_revents & EPOLLHUP)
        {
            if (_closecb != nullptr)
                _closecb();
        }
        else
        {
            LOG(DEG, "unknown event");
        }
        //因为连接的关闭释放操作放到了本轮所有事件处理完毕之后进行 所以对一个连接的事件处理后 连接一定不会被立即关闭 因此在事件处理之后执行任意事件回调是安全的操作
        if (_eventscb != nullptr)
            _eventscb();//对于监听连接来说 没有设置events回调 因此读事件触发时只会执行读事件回调
    }
};

#endif
